﻿#region Copyright (c) 2010 R. Uittenbosch
/*
* Copyright (C) 2010 R. Uittenbosch
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
* associated documentation files (the "Software"), to deal in the Software without restriction, including 
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the 
* following conditions:
* 
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using TouchUI.System.Mobile.Mvc;
using LinkedService.Mobile.ServiceEntities;
using LinkedIn.Mobile.Properties;
using LinkedService.Mobile;
using System.Collections.ObjectModel;

namespace LinkedIn.Mobile
{

  /// <summary>
  /// An update item in our list
  /// </summary>
  public class UpdateListItem : ScrollListItem
  {
    #region Protected variables

    // Some defaults
    public    static int ItemHeight   = Common.Instance.MinimumItemHeight * Common.Instance.ScreenFactor;
    protected static int ImageSize    = Common.Instance.MinimumItemHeight * Common.Instance.ScreenFactor;
    protected static int Spacing      =  2 * Common.Instance.ScreenFactor;
    protected static int HSpacing     = 10 * Common.Instance.ScreenFactor;
    #endregion

    #region variables
    private int row;
   
    private ProfileImage pImage;
    // Should we load images
    private bool LoadImage    = true;
    private int curImageSize  = ImageSize;
    protected int drawfrom    = 0;
    #endregion 

    #region Protected properties
    protected Update update {get; set; }
    protected bool NeedsPicture { get; set; }
    #endregion

    #region Constructor
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="row"></param>
    /// <param name="update"></param>
    public UpdateListItem(int row, Update update)
    {
      // We count from 1
      this.row          = row + 1;
      this.update       = update;
      this.ScreenFactor = Common.Instance.ScreenFactor;
      pImage           = new ProfileImage() { Loaded = false };
      // If there was a picture, show it, otherwise so nothing
      if (update.UpdateContent != null && update.UpdateContent.Person != null)
        if (LoadImage && !string.IsNullOrEmpty(update.UpdateContent.Person.PictureUrl))
          pImage = ProfileImageLoader.Instance.Create(update.UpdateContent.Person.PictureUrl);

      if (update.UpdateContent != null && update.UpdateContent.Person != null)
        ContainedItem = update.UpdateContent.Person; ;
    }

    #endregion

    #region Public properties
    public People People {get; protected set;}
    public string Id { get { return update.UpdateContent.Person != null?update.UpdateContent.Person.Id:string.Empty; } }
    // Update always come from nr 1 distance
    public int Distance { get { return 1; } }
    #endregion

    #region Draw a string on the canvas

    protected int DrawString(Graphics g, int top, int left, string s, Font f, Brush defBrush)
    {
      Brush fontBrush = Selected ? Common.Instance.HighTextBrush : defBrush;
      Size size;
      // Where should we draw
      RectangleF drawRec = new RectangleF(Rectangle.Left + HSpacing + curImageSize + left,
                                              Rectangle.Top + 8 + top,
                                              Rectangle.Width - (16 * ScreenFactor) - left - curImageSize,
                                              ItemHeight);
      // Measure the place needed to draw the string
      size = g.MeasureString(s, f, drawRec);
      g.DrawString(s,
                              f,
                              fontBrush,
                              drawRec,
                              new StringFormat());

      // Where should we draw next
      top += (size.Height + Spacing);
      drawfrom = top;
      Height = drawfrom + 5;
      return top;
    }
    /// <summary>
    /// Draw a string on the canvas
    /// </summary>
    /// <param name="g"></param>
    /// <param name="top"></param>
    /// <param name="left"></param>
    /// <param name="s"></param>
    /// <param name="f"></param>
    /// <returns></returns>
    protected int DrawString(Graphics g, int top, int left, string s, Font f)
    {
      return DrawString(g, top, left, s, f, Common.Instance.FontBrush);
    }
    #endregion

    #region Painting for all updatelistitems
    /// <summary>
    /// Do our custom painting
    /// </summary>
    /// <param name="g"></param>
    public override void Paint(Graphics g)
    {
      if (!string.IsNullOrEmpty(pImage.PictureUrl) && NeedsPicture)
        curImageSize = ImageSize;
      else
        curImageSize = 0;

      // Selected background are different
      Pen pen         = Selected ? Common.Instance.HighTextPen2 : Common.Instance.Pen2;
      Color backcolor = Selected ? SystemColors.Highlight : Color.White;

      // Fill the background
      //g.FillGradientV(new Rectangle(Rectangle.Left + 1, 
      //                              Rectangle.Top + 1, 
      //                              Rectangle.Width - 2, 
      //                              Rectangle.Height - 2), 
      //                              Color.LightGray, backcolor);
      // draw the image
      if (pImage.Loaded && NeedsPicture)
        g.DrawImage(pImage.Picture, new Rectangle(Rectangle.Left /*+ ConnectionListItem.Spacing*/, Rectangle.Top /*+ ConnectionListItem.Spacing*/, UpdateListItem.ImageSize, UpdateListItem.ImageSize),
                           new Rectangle(0, 0, pImage.Picture.Width, pImage.Picture.Height), GraphicsUnit.Pixel);

      int maxstringwidth = Rectangle.Width - UpdateListItem.HSpacing - curImageSize - (16 * ScreenFactor);

      // The person object does not always have to exists
      if (update.UpdateContent != null && update.UpdateContent.Person != null)
      {
        // Draw the name of the person
        string s = Common.Instance.TruncateOneLine(g, update.UpdateContent.Person.Name, Common.Instance.Font, maxstringwidth);
        DrawString(g, 0, 0, s, Common.Instance.SmallBoldFont, Common.Instance.BlueBrush);
      }
    }

    #endregion
  }

  #region ConnectionUpdateListItem
  /// <summary>
  /// Connection update has occured
  /// </summary>
  public class ConnectionUpdateListItem : UpdateListItem
  {
    public ConnectionUpdateListItem(int row, Update update) : base(row,update)
    {
      if (update.UpdateContent.Person != null && update.UpdateContent.Person.Connections != null)
      {
        People = new People() { Items = new Collection<Person>()};
        People.Items.Add(update.UpdateContent.Person);
        foreach (Person p in update.UpdateContent.Person.Connections.Items)
          People.Items.Add(p);        
      }
    }

    /// <summary>
    /// Custom paiting
    /// </summary>
    /// <param name="g"></param>
    public override void Paint(Graphics g)
    {
      // Draw the name of the connected person
      base.Paint(g);
      string conname =string.Empty;
      List<string> names = new List<string>();
      if (update.UpdateContent.Person.Connections.Items != null)
      {
        foreach (Person p in update.UpdateContent.Person.Connections.Items)
          names.Add(p.Name);
        conname = string.Join(", " , names.ToArray());
        int lastcomma = conname.LastIndexOf(",");
        if (lastcomma != -1)
        {
          conname.Remove(lastcomma, 1); // Remove it
          conname.Insert(lastcomma, string.Format(" {0}",Strings.And)); // Add 'and'
        }
      }
      DrawString(g, drawfrom, 0, string.Format(Strings.ConnectedToUpdate , conname), Common.Instance.SmallFont);
    }
  }

  #endregion

  #region StatusUpdateListItem

  /// <summary>
  /// Status update has occured
  /// </summary>
  public class StatusUpdateListItem : UpdateListItem
  {
    public StatusUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    /// <summary>
    /// Custom painting
    /// </summary>
    /// <param name="g"></param>
    public override void Paint(Graphics g)
    {
      base.Paint(g);
      // Draw the current status string
      string status = update.UpdateContent.Person.CurrentStatus;
      DrawString(g, drawfrom, 0, string.Format("{0}", status), Common.Instance.SmallFont);
    }
  }

  #endregion


  #region ProfessionUpdateListItem

  /// <summary>
  /// Someone's profession has changed
  /// </summary>
  public class ProfessionUpdateListItem : UpdateListItem
  {
    public ProfessionUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      string prof = string.Empty;
      // Is there a title ?
      if (update.UpdateContent.Person.Positions != null)
        if (update.UpdateContent.Person.Positions.Count > 0)
          prof = update.UpdateContent.Person.Positions[0].Title;

      if (string.IsNullOrEmpty(prof))
        prof = update.UpdateContent.Person.Headline;

      DrawString(g, drawfrom, 0, string.Format(Strings.PositionsUpdate, prof), Common.Instance.SmallFont);
    }
  }

  #endregion

  #region GroupUpdateListItem

  /// <summary>
  /// Someone joined a group
  /// </summary>
  public class GroupUpdateListItem : UpdateListItem
  {
    public GroupUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      string groupname = string.Empty;
      if (update.UpdateContent.Person.MemberGroups != null)
        if (update.UpdateContent.Person.MemberGroups.Count > 0)
          groupname = update.UpdateContent.Person.MemberGroups[0].Name;

      // Display groupname
      DrawString(g, drawfrom, 0, string.Format(Strings.GroupUpdate ,groupname), Common.Instance.SmallFont);
    }
  }

  #endregion

  #region ProfileUpdateListItem

  /// <summary>
  /// Someone's profile updated
  /// </summary>
  public class ProfileUpdateListItem : UpdateListItem
  {
    public ProfileUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      DrawString(g, drawfrom, 0, Strings.ProfileUpdate , Common.Instance.SmallFont);
    }
  }

  #endregion

  #region PictureUpdateListItem

  /// <summary>
  /// A new picture
  /// </summary>
  public class PictureUpdateListItem : UpdateListItem
  {
    public PictureUpdateListItem(int row, Update update)
      : base(row, update)
    {
      NeedsPicture = true;
    }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      // The picture will already be shown, just say that it changed.
      DrawString(g, drawfrom, 0, Strings.PictureUpdate , Common.Instance.SmallFont);
      if (Height < UpdateListItem.ImageSize)
        Height = UpdateListItem.ImageSize+5;
    }
  }

  #endregion

  #region NewConnectionUpdateListItem

  /// <summary>
  /// A new picture
  /// </summary>
  public class NewConnectionUpdateListItem : UpdateListItem
  {
    public NewConnectionUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      DrawString(g, drawfrom, 0, Strings.ConnectionUpdate , Common.Instance.SmallFont);
    }
  }
  #endregion

  #region OtherUpdateListItem
  /// <summary>
  /// An update that has not yet been specified
  /// </summary>
  public class OtherUpdateListItem : UpdateListItem
  {
    public OtherUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      // What kind of update was it?
      DrawString(g, drawfrom, 0, string.Format(Strings.OtherUpdate , update.UpdateType), Common.Instance.SmallFont);
    }
  }

  #endregion

  #region ApplicationUpdateListItem
  /// <summary>
  /// An update of an application
  /// </summary>
  public class ApplicationUpdateListItem : UpdateListItem
  {
    public ApplicationUpdateListItem(int row, Update update)
      : base(row, update)
    { }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      Activity activity = null;
      if (update.UpdateContent.Person.Activities != null && update.UpdateContent.Person.Activities.Count > 0)
        activity = update.UpdateContent.Person.Activities[0];

      if (activity != null)
        DrawString(g, drawfrom, 0, HtmlStripper.Strip(activity.Body), Common.Instance.SmallFont);
    }
  }

  #endregion

  #region RecommendationUpdateListItem
  /// <summary>
  /// An update of an Recommendation 
  /// </summary>
  public class RecommendationUpdateListItem : UpdateListItem
  {
    public RecommendationUpdateListItem(int row, Update update)
      : base(row, update)
    {
      if (update.UpdateContent.Person != null && update.UpdateContent.Person.ReceivedRecommendations != null)
      {
        People = new People() { Items = new Collection<Person>() };
        People.Items.Add(update.UpdateContent.Person);
        foreach (Recommendation p in update.UpdateContent.Person.ReceivedRecommendations)
          People.Items.Add(p.Recommender);
      }
      else if (update.UpdateContent.Person != null && update.UpdateContent.Person.GivenRecommendations != null)
      {
        People = new People() { Items = new Collection<Person>() };
        People.Items.Add(update.UpdateContent.Person);
        foreach (Recommendation p in update.UpdateContent.Person.GivenRecommendations)
          People.Items.Add(p.Recommendee);
      }

    }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      if (update.UpdateContent.Person.ReceivedRecommendations != null && update.UpdateContent.Person.ReceivedRecommendations.Count > 0)
        if (update.UpdateContent.Person.ReceivedRecommendations[0].Recommender != null)
          DrawString(g, drawfrom, 0, string.Format(Strings.RecommendationUpdate,
            update.UpdateContent.Person.ReceivedRecommendations[0].Recommender.Name,
                  update.UpdateContent.Person.ReceivedRecommendations[0].Snippet
                  )
                  , Common.Instance.SmallFont);

      if (update.UpdateContent.Person.GivenRecommendations != null && update.UpdateContent.Person.GivenRecommendations.Count > 0)
        if (update.UpdateContent.Person.GivenRecommendations[0].Recommendee != null)
            DrawString(g, drawfrom, 0, string.Format(Strings.RecommendationUpdateGiven,
              update.UpdateContent.Person.GivenRecommendations[0].Recommendee.Name,
                    update.UpdateContent.Person.GivenRecommendations[0].Snippet
                    )
                    , Common.Instance.SmallFont);
    }
  }

  #endregion

  #region JobPostingUpdateListItem
  /// <summary>
  /// An update of an Jobposting 
  /// </summary>
  public class JobPostingUpdateListItem : UpdateListItem
  {
    public JobPostingUpdateListItem(int row, Update update)
      : base(row, update)
    {
      // Set the poster as the contained person
      if (update.UpdateContent.Job != null && update.UpdateContent.Job.Poster != null)
      {
        ContainedItem = update.UpdateContent.Job.Poster;
        update.UpdateContent.Person = update.UpdateContent.Job.Poster;
      }
    }

    public override void Paint(Graphics g)
    {
      base.Paint(g);
      if (update.UpdateContent.Job != null)
        if (update.UpdateContent.Job.Position != null && update.UpdateContent.Job.Position.Company != null)      
          DrawString(g, drawfrom, 0, string.Format(Strings.JobPostUpdate,
                  update.UpdateContent.Job.Position.Title,
                  update.UpdateContent.Job.Position.Company.Name)
                  , Common.Instance.SmallFont);
    }
  }

  #endregion
}
